home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / b / b.lha / B / src / bint / b3err.c < prev    next >
C/C++ Source or Header  |  1988-11-24  |  10KB  |  447 lines

  1. /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
  2.  
  3. /*
  4.   $Header: b3err.c,v 1.4 85/08/22 16:57:50 timo Exp $
  5. */
  6.  
  7. /* B error message handling */
  8.  
  9. /* There are two kinds of errors:
  10.     1) parsing, when the line in error is in a buffer
  11.     2) execution, when the line in error is a parse-tree, and must
  12.        therefore be reconstructed.
  13. */
  14.  
  15. /* All error messages are collected in a file, both to save data space
  16.    and to ease translation to other languages.    The English version
  17.    of the database can be recreated from the program sources by scanning
  18.    for the pattern "MESS(".  This is a macro whose first argument is
  19.    the message number and whose second number is the message string;
  20.    this macro expands to only the message number which is passed to
  21.    the error routines.    The error routines then dig the message from
  22.    the error message file, or just print the number if the file can't be
  23.    opened.  There is also a way to pass a message that is determined
  24.    at runtime.
  25. */
  26.  
  27. #include "b.h"
  28. #include "b0fea.h"
  29. #include "b0fil.h"
  30. #include "b1obj.h"
  31. #include "b2syn.h"
  32. #include "b3env.h"
  33. #include "b3fil.h"
  34. #include "b3err.h"
  35. #include "b3scr.h"
  36. #include "b3sig.h"
  37. #include "b3sou.h"
  38.  
  39. Visible bool still_ok, interrupted;
  40.  
  41. Visible parsetree curline= Vnil;
  42. Visible value curlino;
  43. Visible context how_context, act_context;
  44.  
  45. FILE *errfile;    /* The first thing a visible routine must do is set this */
  46.         /* usually by calling line()                 */
  47.  
  48. #define Interactive (errfile == stderr)
  49.  
  50. /*********************************************************************/
  51.  
  52. /* While we are reading the Messages file, we build an index.
  53.    probe[k] contains the first message number found in block k.
  54.    blocks are BUFSIZ in size. */
  55.  
  56. #define FILESIZE 12916 /* Approximated current size of Messages file */
  57. #define MAXPROBE (10 + FILESIZE/BUFSIZ) /* Allow some growth */
  58.  
  59. Hidden short probe[MAXPROBE];
  60. Hidden int nprobes= 1;
  61.  
  62. Hidden FILE *messfp;
  63. Hidden string savedmess;
  64.  
  65. Visible int MESSMAKE(mess) string mess; {
  66.     savedmess= mess;
  67.     return -1;
  68. }
  69.  
  70. Visible string getmess(nr) int nr; {
  71.     int last, c; char *cp= NULL;
  72.     static char buf[80]; bool new; int block; long ftell();
  73.     char *filename;
  74.     if (nr == 0) return "";
  75.     if (nr < 0) { return savedmess; }
  76.     if (messfp == NULL)
  77.         messfp= fopen(messfile, "r");
  78.     if (messfp) {
  79.         for (block= nprobes-1; block > 0; --block) {
  80.             if (probe[block] <= nr)
  81.                 break;
  82.         }
  83.         new= block == nprobes-1;
  84.         fseek(messfp, (long)block*BUFSIZ, 0);
  85.         last= 0;
  86.         while (last < nr) {
  87.             if (new) block= ftell(messfp) / BUFSIZ;
  88.             if (fgets(buf, sizeof buf, messfp) == NULL) break;
  89.             last= atoi(buf);
  90.             if (last <= 0)
  91.                 continue;
  92.             if (new && block >= nprobes && nprobes < MAXPROBE) {
  93.                 probe[block]= last;
  94.                 nprobes= block+1;
  95.             }
  96.         }
  97.         if (last == nr) {
  98.             cp= index(buf, '\n');
  99.             if (cp != NULL) *cp = '\0'; /* strip terminating \n */
  100.             cp= buf;
  101.             cp= index(buf, '\t');
  102.             if (cp != NULL) return cp+1;
  103.         }
  104.     }
  105.     sprintf(buf, " (error %d) ", nr);
  106.     return buf;
  107. }
  108.  
  109. Hidden Procedure prmess(nr) int nr; {
  110.     errmess(getmess(nr));
  111. }
  112.  
  113. /*********************************************************************/
  114.  
  115. Hidden Procedure putch(c) char c; {
  116.     putc(c, errfile);
  117. }
  118.  
  119. Hidden Procedure line() {
  120. #ifdef EXT_COMMAND
  121.     e_done();
  122. #endif
  123.     fflush(stdout);
  124.     if (cntxt == In_read) {
  125.         if (rd_interactive) {
  126.             errfile= stderr; at_nwl= Yes;
  127.         } else errfile= stdout;
  128.     } else if (interactive) errfile= stderr;
  129.            else errfile= stdout;
  130.     if (!at_nwl) putch('\n');
  131.     at_nwl= Yes;
  132. }
  133.  
  134. Hidden Procedure errmess(m) string m; {
  135.     fputs(m, errfile);
  136. }
  137.  
  138. #ifdef NOT_USED
  139. Hidden Procedure core_dump() {
  140.     errmess("*** Core-dump for inspection purposes: ");
  141.     fflush(stdout);
  142.     dump();
  143. }
  144. #endif
  145.  
  146. Hidden Procedure prname(name) value name; {
  147.     if (Is_text(name)) {
  148.         still_ok= Yes;
  149.         writ(name);
  150.         still_ok= No;
  151.     }
  152. }
  153.  
  154. Visible value erruname= Vnil;
  155. Visible intlet errlino= 0;
  156.  
  157. Hidden intlet pr_line(at) bool at; {
  158.     /*prints the line that tx is in, with an arrow pointing to the column
  159.       that tx is at.
  160.     */
  161.     txptr lx= fcol(); intlet ap= -1, p= 0; char c; txptr ax= tx;
  162.     if (!at) do ax--; while (Space(Char(ax)));
  163.     while (!Eol(lx) && Char(lx) != Eotc) {
  164.         if (lx == ax) ap= p;
  165.         c= *lx++;
  166.         if (c == '\t') {
  167.             do { putch(' '); } while (((++p)%4)!=0);
  168.         } else { putch(c); p++; }
  169.     }
  170.     putch('\n');
  171.     if (ap < 0) ap= p;
  172.     for (p= 0; p < ap+4; p++) putch(' ');
  173.     errmess("^\n");
  174. }
  175.  
  176. Hidden bool sh_lino(lino) intlet lino; {
  177.     switch (cntxt) {
  178.         case In_command:
  179.         case In_read:
  180.         case In_edval:
  181.         case In_tarval:
  182.         case In_prmnv:    return No;
  183.         case In_unit:    return lino != 1;
  184.         default:    return Yes;
  185.     }
  186. }
  187.  
  188.  
  189. Hidden Procedure show_line(in_node, at, node, line_no)
  190.  bool in_node, at; parsetree node; int line_no;
  191.  {
  192.     if (sh_lino(line_no))
  193.         fprintf(errfile, " in line %d of your ", line_no);
  194.     else
  195.         errmess(" in your ");
  196.     switch (cntxt) {
  197.         case In_command:    errmess("command"); break;
  198.         case In_read:        errmess("expression to be read"); break;
  199.         case In_edval:        errmess("edited value"); break;
  200.         case In_tarval:     errmess("target value"); break;
  201.         case In_unit:        errmess("unit ");
  202.                     release(erruname);
  203.                     if (Is_text(uname)) {
  204.                         value name; literal type;
  205.                         p_name_type(uname, &name, &type);
  206.                         prname(name); release(name);
  207.                         erruname= copy(uname);
  208.                         errlino= line_no;
  209.                     } else erruname= Vnil;
  210.                     break;
  211.         case In_prmnv:        errmess("permanent environment"); break;
  212.         default:        errmess("???\n"); return;
  213.     }
  214.     errmess("\n");
  215.     if (!in_node || node != Vnil) errmess("    ");
  216.     if (in_node) display(errfile, node, Yes);
  217.     else pr_line(at);
  218. }
  219.  
  220. Hidden bool unit_file() {
  221.     value *aa;
  222.     return cntxt == In_unit && Is_text(uname) && p_exists(uname, &aa);
  223. }
  224.  
  225. Hidden Procedure show_where(in_node, at, node)
  226.     bool in_node, at; parsetree node; {
  227.  
  228.     int line_no= in_node ? intval(curlino) : lino;
  229.     if (cntxt == In_formal) { /*can only happen when in_node*/
  230.         context cc;
  231.         sv_context(&cc);
  232.         set_context(&how_context);
  233.         copy(uname);
  234.         show_line(Yes, Yes, curline, intval(curlino));
  235.         errmess("*** originating");
  236.         set_context(&act_context);
  237.         copy(uname);
  238.         show_line(Yes, Yes, curline, intval(curlino));
  239.         set_context(&cc);
  240.     } else
  241.         show_line(in_node, at, node, line_no);
  242.     if (!Interactive && !unit_file()) {
  243.         fprintf(errfile,
  244.           "*** (detected after reading %d input line%s of your input file ",
  245.             f_lino, f_lino == 1 ? "" : "s");
  246.         if (iname == Vnil) errmess("standard input");
  247.         else prname(iname);
  248.         errmess(")\n");
  249.     }
  250. }
  251.  
  252. Hidden Procedure fatal(m, in_node) int m; bool in_node; {
  253.     line();
  254.     errmess("*** Sorry, B system malfunction");
  255.     show_where(in_node, Yes, curline);
  256.     errmess("*** The problem is: ");
  257.     prmess(m); errmess("\n");
  258.     errmess("*** Please save pertinent data for inspection by B guru\n");
  259.     bye(-1);
  260. }
  261.  
  262. Visible Procedure syserr(m) int m; {
  263.     fatal(m, Yes);
  264. }
  265.  
  266. #ifdef EXT_COMMAND
  267. Visible Procedure psyserr(m) int m; {
  268.     fatal(m, No);
  269. }
  270. #endif
  271.  
  272. Visible Procedure memexh() {
  273.     line();
  274.     errmess("*** Sorry, memory exhausted");
  275. /* show_where(Yes, Yes); don't know if in node or not; to fix */ errmess("\n");
  276.     errmess("*** Get your boss to buy a larger computer\n");
  277.     bye(-1);
  278. }
  279.  
  280. Hidden Procedure fix_files() {
  281.     if (ifile != stdin) fclose(ifile);
  282.     if (f_interactive(stdin) || filtered) {
  283.         interactive= Yes;
  284.         release(iname);
  285.         iname = Vnil;
  286.         ifile = stdin;
  287.         sv_ifile= ifile;
  288.         Eof= No;
  289.     }
  290. }
  291.  
  292. Hidden Procedure message(m1, m2, v, m3, in_node, at)
  293.  string m1; int m2, m3; value v; bool in_node, at; {
  294.     still_ok= No;
  295.     line();
  296.     errmess(m1);
  297.     show_where(in_node, at, curline);
  298.     errmess("*** The problem is: ");
  299.     prmess(m2);
  300.     if (v != Vnil) errmess(strval(v));
  301.     prmess(m3);
  302.     errmess("\n");
  303.     at_nwl=Yes;
  304. }
  305.  
  306. Visible Procedure pprerr(m) int m; {
  307.     if (still_ok)
  308.     message("*** There's something I don't understand", m, Vnil, 0, No, No);
  309. }
  310.  
  311. Visible Procedure pprerr2(tag, m) value tag; int m; {
  312.     if (still_ok)
  313.     message("*** There's something I don't understand", 0, tag, m, No, No);
  314. }
  315.  
  316. Visible Procedure parerr2(m, ss) int m, ss; {
  317.     if (still_ok)
  318.     message("*** There's something I don't understand", m, Vnil, ss, No, Yes);
  319. }
  320.  
  321. Visible Procedure parerr(m) int m; {
  322.     parerr2(m, 0);
  323. }
  324.  
  325. Visible Procedure fixerr3(m1, v, m2) value v; int m1, m2; {
  326.     if (still_ok)
  327.     message("*** There's something I can't resolve", m1, v, m2, Yes, Yes);
  328. }
  329.  
  330. Visible Procedure fixerr2(v, m) value v; int m; {
  331.     fixerr3(0, v, m);
  332. }
  333.  
  334. Visible Procedure fixerr(m) int m; {
  335.     fixerr3(0, Vnil, m);
  336. }
  337.  
  338. Visible Procedure error3(m1, v, m2) value v; int m1, m2; {
  339.     message("*** Can't cope with problem", m1, v, m2, Yes, No);
  340. }
  341.  
  342. Visible Procedure error2(m, v) int m; value v; {
  343.     error3(m, v, 0);
  344. }
  345.  
  346. Visible Procedure error(m) int m; {
  347.     error3(m, Vnil, 0);
  348. }
  349.  
  350. Visible Procedure checkerr() {
  351.     still_ok= No;
  352.     line();
  353.     errmess("*** Your check failed");
  354.     show_where(Yes, No, curline);
  355.     at_nwl= Yes;
  356. }
  357.  
  358. #ifdef SIGNAL
  359.  
  360. Visible Procedure int_signal() {
  361.     interrupted= Yes; still_ok= No;
  362.     if (cntxt == In_prmnv) exit(-1);
  363.     if (!interactive) fix_files();
  364.     if (!interactive) bye(1);
  365.     line(); fflush(stdout);
  366.     errmess("*** interrupted\n");
  367. #ifndef INTEGRATION
  368.     if (filtered) errmess("\177");
  369. #endif
  370.     if (cntxt == In_read) {
  371.         set_context(&read_context);
  372.         copy(uname);
  373.     }
  374.     at_nwl= Yes;
  375. }
  376.  
  377. #endif SIGNAL
  378.  
  379. Visible bool bugs= No, testing= No, tracing= No;
  380.  
  381. #ifdef NOT_USED
  382. Visible Procedure debug(m) string m; {
  383.     if (bugs) {
  384.         line();
  385.         errmess("*** Debugging ");
  386.         show_where(Yes, Yes, curline);
  387.         fprintf(errfile, "*** %s\n", m);
  388.         at_nwl= Yes;
  389.     }
  390. }
  391. #endif
  392.  
  393. #ifdef EXT_COMMAND
  394.  
  395. /* User-callable error message */
  396. Visible Procedure e_error(mesg) value mesg; {
  397.     value v= convert(mesg, Yes, Yes);
  398.     message("*** Halted", 0, v, 0, Yes, No);
  399.     release(v);
  400. }
  401.  
  402. #endif
  403.  
  404. Visible Procedure bye(ex) int ex; {
  405. #ifdef EXT_COMMAND
  406.     e_done();
  407. #endif
  408.     at_nwl= Yes;
  409.     putprmnv();
  410.     endall();
  411.     if (ex == 0) {
  412.         term_mem();
  413.         endmem();
  414.     }
  415. #ifdef IBMPC
  416.     memstat("at end");
  417. #endif IBMPC
  418.     exit(ex);
  419. }
  420.  
  421. Visible Procedure initerr() {
  422.     still_ok= Yes; interrupted= No; curline= Vnil; curlino= zero;
  423. }
  424.  
  425.  
  426. #define HZ 60 /* 4.2BSD: not line frequency but historical constant */
  427.  
  428. showtime(whence)
  429.     string whence;
  430. {
  431. #ifdef TIMING
  432.     static long total[2];
  433.     long buf[4];
  434.     extern bool timing; /* Set in b3mai.c by -T option */
  435.  
  436.     if (!timing) return;
  437.     times(buf);
  438.     line();
  439.     fprintf(errfile, "*** Times %s: user %.2f sys %.2f (total %.2f %.2f)\n",
  440.         whence,
  441.         (float)(buf[0]-total[0])/HZ, (float)(buf[1]-total[1])/HZ,
  442.         (float)total[0]/HZ, (float)total[1]/HZ
  443.     );
  444.     total[0]= buf[0]; total[1]= buf[1];
  445. #endif TIMING
  446. }
  447.